class Stack{
    constructor(){
        this.count = 0 //栈的计数器
        this.items = {} //栈的数据仓库
    }
    push(...eles){ //添加一个值
        for(let i = 0,len = eles.length; i < len; i++){
            this.items[this.count] = eles[i] //采用计数器当前值（自然数）为下标key，存储实际数据
            this.count++ //每次push进一个数据，计数器自增1
        }
    }
    size(){ //返回栈的长度
        return this.count //每次查询的时候直接返回当前的计数器的值
    }
    isEmpty(){ //判断栈是否为空
        return !this.count //判断是否为空，直接返回计数器的取反，0取反为true，大于零取反为false
    }
    pop(){ //删除栈顶值并返回被删除的值
        if(this.isEmpty()){ //先进行判断，如果栈内为空，直接返回undefined
            return undefined
        }

        //如果不走上面的if判断则表明栈非空，那么就走下面的代码
        this.count-- //先进行计数器自减1，减去1之后得到的就是未删除前栈顶值的下标key，如果不明白，用几个数代入就知道了
        let result = this.items[this.count] //得到栈顶的值
        delete this.items[this.count] //删除栈顶的值
        return result //并返回被删除的栈顶的值
    }
    peek(){ //返回栈顶的值不对栈做任何修改
        if(this.isEmpty()){ //先进行判断，如果栈内为空，直接返回undefined
            return undefined
        }
        return this.items[this.count - 1] //否则返回当前的栈顶值
    }
    clear(){ //清空栈内数据
        while(!this.isEmpty()){ //当栈内为非空则一直进行这个循环，pop删除直到栈内没有数据为止
            this.pop()
        }
    }
    toString(){ //转字符串
        if(this.isEmpty()){ //先进行判断，如果栈内为空，直接返回空字符串""
            return ""
        }
        let resultString = "" //如果非空则先用一个变量保存，因为我们也不知道有多少个值，默认为空字符串
        for(let i = 0; i < this.count; i++){
            resultString = `${resultString},${this.items[i]}` //如果无法理解，代入几个数进去即可明白
        }
        return resultString.slice(1) //因为上面的模板字符串拼接方式会在第一位返回多一个逗号，所以要用slice方法删除逗号
    }
    forEach(cb){ //forEach方法接收一个回调函数
        for(let i = 0; i < this.count; i++){
            cb(i,this.items[i],this) //回调函数接收三个参数index，items，arr本身
        }
    }
    [Symbol.iterator](){ //手动添加一个迭代器接口
        let self = this //先保存好当前的this
        let index = 0 //定义一个索引
        return {
            next(){
                if(index < self.count){ //如果没有遍历结束，则一个个返回当前值
                    return {
                        value:self.items[index++], //运用了闭包
                        done:false //false表示没有遍历完成
                    }
                }else{ //否则如果变量结束，则返回undefined
                    return {
                        value:undefined,
                        done:true //true表示遍历结束
                    }
                }
            }
        }
    }
}

let arr = new Stack()
    //用我们刚刚的栈
/*
* 汉诺塔的游戏规则：
*   1、当第一根柱子只有一个滑块的时候，直接把第一根柱子上的滑块移到第三根柱子
*   2、当第一根柱子不只一个滑块的时候，把除去最下面一个滑块以外的其余滑块都移到第二根柱子，然后又回到了第一种状态
*
* */

function hanoi(plates = 3,A,B,C,moves = []){
    if(plates <= 0){ //当A柱子上没有滑块的情况，直接结束游戏，返回默认的栈值为空
        return moves
    }
    if(plates === 1){ //当A柱子上只有一个滑块的情况
        moves.push([A,C]) //栈内添加该数组，直接滑块从A到C
    }else{ //当A柱子上不只一个滑块的情况，把除了最下面那个滑块以外的所有滑块都移到B柱子
        hanoi(plates - 1,A,C,B,moves) //此时除了最下面那个滑块其余全到到了B柱子，又回到第一种情况
        moves.push([A,C]) //栈内添加该数组，直接滑块从A到C
        hanoi(plates - 1,B,A,C,moves)
    }
    return moves
}

console.log(hanoi(3,"第一根","第二根","第三根"))